//
//  KuKu_Web.m
//  kuku
//
//  Created by 清风徐来 on 2024/1/23.
//

#import "KuKu_Web.h"
#import <kuku/KuKu_Util.h>
#import <kuku/kuku-Swift.h>

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"

@interface KuKu_Web () <WKScriptMessageHandler, WKNavigationDelegate>

@property(nonatomic, strong) WKWebView * webView;
@property(nonatomic, strong) UIActivityIndicatorView *indicatorView;
@property(nonatomic, strong) UILabel *progressLabel;
@property(nonatomic, strong) UIViewController * webController;
@property(nonatomic, strong) NSArray <NSString *>*jsNames;

@end

@implementation KuKu_Web

static KuKu_Web *_sharedInstance;
+ (instancetype)shared {
    if(_sharedInstance == nil) {
        _sharedInstance = [[KuKu_Web alloc] init];
    }
    return _sharedInstance;
}

+(instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [super allocWithZone:zone];
    });
    return _sharedInstance;
}

- (id)copyWithZone:(NSZone *)zone {
    return _sharedInstance;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    return _sharedInstance;
}

- (NSArray <NSString *>*)getJsWithMotheds {
    return @[@"getAppBundleId",
             @"getAppVersion",
             @"openUrl",
             @"removeAllCached",
             @"removeAllCookie",
             @"savePicture",
             @"setApplicaitonBadgeValue",
             @"getPhoneModel",
             @"getPhoneOs"];
}

/// 设置JS交互
/// - Parameters:
///   - jsNames: 交互名数组
///   - webView: webview
///   - controller: 需要跳转的Web Controller
- (void)registerJsWithMotheds:(NSArray <NSString *>*)jsNames {
    self.jsNames = jsNames;

    // 再进入Web
    NSString *link = [KuKu_Plist loadLinkFromPlist];
    link = [NSString stringWithFormat:@"https://h5.%@.com", link];
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:link]]];
    dispatch_async(dispatch_get_main_queue(), ^{
        [[UIApplication sharedApplication].delegate.window setRootViewController:self.webController];
        [[UIApplication sharedApplication].delegate.window makeKeyAndVisible];
    });
}

//MARK: - WKScriptMessageHandler

- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message { 
    NSString * jsName = message.name;
    if (jsName == nil || jsName.length <= 0) {
        return;
    }
    if ([jsName isEqualToString:@"getAppBundleId"]) {
        // 获取Bundle id
        NSString *bundleId = [KuKu_Plist loadBundleIdFromPlist];
        [self sendJsMessage:[NSString stringWithFormat:@"%@('%@')",jsName, bundleId] webView:message.webView];
    } else if ([jsName isEqualToString:@"getAppVersion"]) {
        // 获取APP版本
        NSString *appVersion = [KuKu_Plist loadVersionFromPlist];
        [self sendJsMessage:[NSString stringWithFormat:@"%@('%@')",jsName, appVersion] webView:message.webView];
    } else if ([jsName isEqualToString:@"openUrl"]) {
        // 打开URL
        if (message.body) {
            NSString *link = message.body;
            [KuKu_LinK openLinkWith:[NSURL URLWithString:link]];
        }
    } else if ([jsName isEqualToString:@"removeAllCached"]) {
        // 移除所有缓存
        [self removeAllCached];
    } else if ([jsName isEqualToString:@"removeAllCookie"]) {
        // 移除所有cookies
        [self removeAllCookie];
    } else if ([jsName isEqualToString:@"savePicture"]) {
        // 保存图片
        NSString *pictureString = (NSString *)message.body;
        if (pictureString == nil || pictureString.length <= 0) {
            return;
        }
        UIImage *img = [KuKu_Image stringToImage:pictureString];
        if (img == nil) {
            return;
        }
        UIImageWriteToSavedPhotosAlbum(img, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
    } else if ([jsName isEqualToString:@"setApplicaitonBadgeValue"]) {
        // 设置应用角标
        NSNumber *badgeNumber = (NSNumber *)message.body;
        [UIApplication.sharedApplication setApplicationIconBadgeNumber:badgeNumber.intValue];
    } else if ([jsName isEqualToString:@"getPhoneModel"]) {
        // 获取手机model型号
       NSString *deviceModel = [KuKu_Device getAppDeviceModel];
        [self sendJsMessage:[NSString stringWithFormat:@"%@('%@)",jsName, deviceModel] webView:message.webView];
    } else if ([jsName isEqualToString:@"getPhoneOs"]) {
        // 获取手机OS
       NSString *osVersion = [KuKu_Device getAppDeviceOsVersion];
        [self sendJsMessage:[NSString stringWithFormat:@"%@('%@)",jsName, osVersion] webView:message.webView];
    } else {
        NSLog(@"Received other messages：%@", message.body);
    }

    [self sendJsMessage:[NSString stringWithFormat:@"%@()", jsName] webView:message.webView];
}

/**
 KVO获取网页title
 @param keyPath 路径
 @param object 对象
 @param change 改变
 @param context 上下文
 */
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"estimatedProgress"]) {
        if ([object isEqual:self.webView]) {
            [self.progressLabel setText:[NSString stringWithFormat:@"资源加载中(%.1f%%)...", self.webView.estimatedProgress * 100]];
            if (self.webView.estimatedProgress > 0 && self.webView.estimatedProgress < 1) {
                self.progressLabel.hidden = NO;
                [self.indicatorView startAnimating];
            } else if (self.webView.estimatedProgress == 1) {
                __weak typeof(self) weakSelf = self;
                dispatch_async(dispatch_get_main_queue(), ^{
                    [weakSelf.indicatorView stopAnimating];
                    weakSelf.progressLabel.hidden = YES;
                    [weakSelf.progressLabel setText:@""];
                    weakSelf.webView.hidden = NO;
                });
            }
        }
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

#pragma mark -WKNavigationDelegate
///发送请求之前 决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    NSLog(@"--发送请求之前 决定是否跳转-decidePolicyForNavigationAction");
    NSLog(@"%@",navigationAction.request.URL.absoluteString);
    //允许跳转
    decisionHandler(WKNavigationActionPolicyAllow);
}

///页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
    NSLog(@"--页面开始加载调用-didStartProvisionalNavigation");
}

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
    NSLog(@"--接收到响应后，决定是否跳转--decidePolicyForNavigationResponse");
    NSLog(@"%@",navigationResponse.response.URL.absoluteString);
    //允许跳转
    decisionHandler(WKNavigationResponsePolicyAllow);
}

- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
    NSLog(@"--当内容开始返回时调用-didCommitNavigation");
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    NSLog(@"--页面加载完成之后调用-didFinishNavigation");
}

- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
    NSLog(@"--接收到服务器跳转请求之后-didReceiveServerRedirectForProvisionalNavigation");
}

- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
    NSLog(@"--页面加载失败调用-didFailProvisionalNavigation");
}

#pragma mark -WKUIDelegate
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
    NSLog(@"--创建一个新的webView-createWebViewWithConfiguration");
    return [[WKWebView alloc] init];
}

// 输入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {
    NSLog(@"%@---%@",prompt, defaultText);
    completionHandler(@"http");
}

// 确认框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
    NSLog(@"%@",message);
    completionHandler(YES);
}

// 警告框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
    NSLog(@"%@",message);
    completionHandler();
}

- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
    [webView reload];
}

- (void)dealloc {
    [self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
}

#pragma mark -- <保存到相册>
-(void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
    NSString *msg = nil ;
    if(error) {
        msg = @"保存图片失败" ;
    }else{
        msg = @"保存图片成功" ;
    }
    [self sendJsMessage:[NSString stringWithFormat:@"savePicture(%@)", msg] webView:self.webView];
}

/// Send JS information
-(void)sendJsMessage:(NSString *)message webView:(WKWebView *)webView {
    NSLog(@"Message to be sent soon = %@", message);
    // Send js message
    [webView evaluateJavaScript:message completionHandler:^(id _Nullable response, NSError * _Nullable error) {
        if (error) {
            NSLog(@"发送JS消息失败: %@", error);
        }else {
            NSLog(@"发送JS消息成功");
        }
    }];
}

// 清除WKWebView的所有缓存
- (void)removeAllCached {
    [[WKWebsiteDataStore defaultDataStore] fetchDataRecordsOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] completionHandler:^(NSArray<WKWebsiteDataRecord *> * _Nonnull records) {
        for (WKWebsiteDataRecord *record in records) {
            [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:record.dataTypes forDataRecords:@[record] completionHandler:^{
                // 清除完成后的回调
                NSLog(@"清除缓存成功");
            }];
        }
    }];
}

// 清除WKWebView Cookie缓存
- (void)removeAllCookie {
    WKWebsiteDataStore *dataStore = [WKWebsiteDataStore defaultDataStore];
    NSSet *websiteDataTypes = [NSSet setWithObject:WKWebsiteDataTypeCookies];
    [dataStore fetchDataRecordsOfTypes:websiteDataTypes completionHandler:^(NSArray<WKWebsiteDataRecord *> * _Nonnull records) {
        for (WKWebsiteDataRecord *record in records) {
            [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:record.dataTypes forDataRecords:@[record] completionHandler:^{
                NSLog(@"Cookies 已清除");
            }];
        }
    }];
}

//MARK: - lazy load

- (WKWebView *)webView {
    if (!_webView) {
        WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
        WKUserContentController *userContentController = [[WKUserContentController alloc] init];
        if (@available(iOS 14.0, *)) {
            WKWebpagePreferences *webpagePreferences = [[WKWebpagePreferences alloc] init];
            webpagePreferences.allowsContentJavaScript = YES;
            configuration.defaultWebpagePreferences = webpagePreferences;
        }else {
            configuration.preferences.javaScriptEnabled = YES;
        }
        configuration.allowsInlineMediaPlayback = YES;
        configuration.preferences.javaScriptCanOpenWindowsAutomatically = YES;
        configuration.suppressesIncrementalRendering = YES;
        configuration.allowsAirPlayForMediaPlayback = YES;
        configuration.allowsInlineMediaPlayback = YES;
        configuration.allowsPictureInPictureMediaPlayback = YES;

        if (self.jsNames == nil || self.jsNames.count == 0) {
            self.jsNames = [self getJsWithMotheds];
        }
        for (NSString *name in self.jsNames) {
            [userContentController addScriptMessageHandler:self name:name];
        }
        configuration.userContentController = userContentController;
        if (@available(iOS 11.0, *)) {
            _webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
        }
        _webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
        _webView.navigationDelegate = self;
        _webView.exclusiveTouch = NO;
        _webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
        _webView.scrollView.bouncesZoom = NO;
        _webView.allowsBackForwardNavigationGestures = YES;//允许右滑手势返回上一页面(网页)
        _webView.scrollView.bounces = NO;
        _webView.hidden = YES;
        ///KVO-estimatedProgress
        [_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:NULL];
    }
    return _webView;
}

- (UIViewController *)webController {
    if (!_webController) {
        _webController = [[UIViewController alloc] init];
        _webController.view.backgroundColor = [UIColor whiteColor];

        [_webController.view addSubview:self.webView];
        self.webView.frame = CGRectMake(0, 0, self.screenWidth, self.screenHeight);

        [_webController.view addSubview:self.indicatorView];
        self.indicatorView.center = _webController.view.center;

        [_webController.view addSubview:self.progressLabel];
        self.progressLabel.frame = CGRectMake(0, CGRectGetMaxY(self.indicatorView.frame) + 10, self.screenWidth, 20);
    }
    return _webController;
}

- (UIActivityIndicatorView *)indicatorView {
    if (!_indicatorView) {
        if (@available(iOS 13.0, *)) {
            _indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleMedium)];
            _indicatorView.hidesWhenStopped = YES;
            _indicatorView.hidden = NO;
        }
    }
    return _indicatorView;
}

- (UILabel *)progressLabel {
    if (!_progressLabel) {
        _progressLabel = [[UILabel alloc] init];
        _progressLabel.textColor = UIColor.lightGrayColor;
        _progressLabel.font = [UIFont systemFontOfSize:14];
        _progressLabel.textAlignment = NSTextAlignmentCenter;
        _progressLabel.hidden = NO;
    }
    return _progressLabel;
}

- (CGFloat)screenWidth {
    return [UIScreen mainScreen].bounds.size.width;
}

- (CGFloat)screenHeight {
    return [UIScreen mainScreen].bounds.size.height;
}

@end

#pragma clang diagnostic pop
